/*  Copyright (c) 2012 William Rogers and James Boud

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/

using System;
using System.Collections.Generic;
using SlimDX;
using SlimDX.Direct3D11;

namespace JBBRXG11
{
    public class BasicEffect : Effect
    {
        const string ShaderSource =
        #region Shader for non animated model
 "#define MaxBones 59\r\n" +
"float4x4 World;\r\n" +
"float4x4 View;\r\n" +
"float4x4 Projection;\r\n" +
"float3 CameraPosition;\r\n" +
"texture2D Texture;\r\n" +
"\r\n" +
"float Alpha = 1;\r\n" +
"float3 AmbientLightColor = float3(0, 0, 0);\r\n" +
"float3 DiffuseColor = float3(1, 1, 1);\r\n" +
"float3 EmissiveColor = float3(0, 0, 0);\r\n" +
"float3 SpecularColor = float3(1, 1, 1);\r\n" +
"float SpecularPower = 16;\r\n" +
"\r\n" +
"bool DLEnabled0 = false;\r\n" +
"bool DLEnabled1 = false;\r\n" +
"bool DLEnabled2 = false;\r\n" +
"\r\n" +
"bool PerPixelLighting = false;\r\n" +
"\r\n" +
"float3 DLDiffuseColor0 = float3(0, 0, 0);\r\n" +
"float3 DLDiffuseColor1 = float3(0, 0, 0);\r\n" +
"float3 DLDiffuseColor2 = float3(0, 0, 0);\r\n" +
"\r\n" +
"float3 DLDirection0 = float3(0, 1, 0);\r\n" +
"float3 DLDirection1 = float3(0, 1, 0);\r\n" +
"float3 DLDirection2 = float3(0, 1, 0);\r\n" +
"\r\n" +
"float3 DLSpecularColor0 = float3(0, 0, 0);\r\n" +
"float3 DLSpecularColor1 = float3(0, 0, 0);\r\n" +
"float3 DLSpecularColor2 = float3(0, 0, 0);\r\n" +
"\r\n" +
"float3 FogColor = float3(0, 0, 0);\r\n" +
"bool FogEnabled = false;\r\n" +
"float FogEnd = 1;\r\n" +
"float FogStart = 0;\r\n" +
"\r\n" +
"float4x4 Bones[MaxBones];\r\n" +
"\r\n" +
"SamplerState samLinear\r\n" +
"{\r\n" +
"    Filter = MIN_MAG_MIP_LINEAR;\r\n" +
"    AddressU = Wrap;\r\n" +
"    AddressV = Wrap;\r\n" +
"};\r\n" +
"\r\n" +
"/* Technique, Input and Vertex Shader cases */\r\n" +
"/* These are just permutations of VertexColour, Texture, and Normal(Lighting) */\r\n" +
"\r\n" +
"/* Case: Vertex Color: False  Texture: False  Normals: False    V0T0N0 */\r\n" +
"/* Case: Vertex Color: False  Texture: False  Normals: True     V0T0N1 */\r\n" +
"/* Case: Vertex Color: False  Texture: True   Normals: False    V0T1N0 */\r\n" +
"/* Case: Vertex Color: False  Texture: True   Normals: True     V0T1N1 */\r\n" +
"/* Case: Vertex Color: True   Texture: False  Normals: False    V1T0N0 */\r\n" +
"/* Case: Vertex Color: True   Texture: False  Normals: True     V1T0N1 */\r\n" +
"/* Case: Vertex Color: True   Texture: True   Normals: False    V1T1N0 */\r\n" +
"/* Case: Vertex Color: True   Texture: True   Normals: True     V1T1N1 */\r\n" +
"\r\n" +
"/* Pixel Shader cases */\r\n" +
"/* Case: Texture: False  Normals: False    T0N0 */\r\n" +
"/* Case: Texture: False  Normals: True     T0N1 */\r\n" +
"/* Case: Texture: True   Normals: False    T1N0 */\r\n" +
"/* Case: Texture: True   Normals: True     T1N1 */\r\n" +
"\r\n" +
"\r\n" +
"/******************************************************************************/\r\n" +
"/* Vertex Case: Vertex Color: False  Texture: False  Normals: False    V0T0N0 */\r\n" +
"/* Vertex Case: Vertex Color: True   Texture: False  Normals: False    V1T0N0 */\r\n" +
"/* Pixel Case: Texture: False  Normals: False    T0N0 */\r\n" +
"/******************************************************************************/\r\n" +
"\r\n" +
"struct VS_IN_V0T0N0\r\n" +
"{\r\n" +
"    float4 Pos: POSITION;\r\n" +
"};\r\n" +
"\r\n" +
"struct VS_IN_V1T0N0\r\n" +
"{\r\n" +
"    float4 Pos: POSITION;\r\n" +
"	float4 Col: COLOR;\r\n" +
"};\r\n" +
"\r\n" +
"struct PS_IN_T0N0\r\n" +
"{\r\n" +
"	float4 Pos: SV_POSITION;\r\n" +
"	float3 WPos: POSITION;\r\n" +
"	float4 Light: COLOR0;\r\n" +
"};\r\n" +
"\r\n" +
"PS_IN_T0N0 VS_V0T0N0( VS_IN_V0T0N0 input )\r\n" +
"{\r\n" +
"    PS_IN_T0N0 output;\r\n" +
"    output.Pos = mul(input.Pos, mul(World, mul(View, Projection)));\r\n" +
"    output.WPos = mul(input.Pos, World).xyz;\r\n" +
"    output.Light = float4(EmissiveColor + DiffuseColor, Alpha);\r\n" +
"    return output;\r\n" +
"}\r\n" +
"\r\n" +
"PS_IN_T0N0 VS_V1T0N0( VS_IN_V1T0N0 input )\r\n" +
"{\r\n" +
"    PS_IN_T0N0 output;\r\n" +
"    output.Pos = mul(input.Pos, mul(World, mul(View, Projection)));\r\n" +
"    output.WPos = mul(input.Pos, World).xyz;\r\n" +
"    output.Light = float4(EmissiveColor, 0) + input.Col * float4(DiffuseColor, Alpha);\r\n" +
"    return output;\r\n" +
"}\r\n" +
"\r\n" +
"float4 PS_T0N0( PS_IN_T0N0 input ) : SV_Target\r\n" +
"{\r\n" +
"   float4 colourout;\r\n" +
"   colourout = input.Light;\r\n" +
"   if (FogEnabled)\r\n" +
"   {\r\n" +
"       float foglevel = saturate((length(CameraPosition - input.WPos) - FogStart)\r\n" +
"                                                             / (FogEnd - FogStart));\r\n" +
"       colourout.rgb = colourout.rgb * (1 - foglevel) + FogColor * foglevel;\r\n" +
"   }\r\n" +
"   return colourout;\r\n" +
"}\r\n" +
"\r\n" +
"technique10 Render_V0T0N0\r\n" +
"{\r\n" +
"    pass P0\r\n" +
"    {\r\n" +
"        SetVertexShader( CompileShader( vs_4_0, VS_V0T0N0() ) );\r\n" +
"        SetHullShader( NULL );\r\n" +
"        SetDomainShader( NULL );\r\n" +
"        SetGeometryShader( NULL );\r\n" +
"        SetPixelShader( CompileShader( ps_4_0, PS_T0N0() ) );\r\n" +
"    }\r\n" +
"}\r\n" +
"\r\n" +
"technique10 Render_V1T0N0\r\n" +
"{\r\n" +
"    pass P0\r\n" +
"    {\r\n" +
"        SetVertexShader( CompileShader( vs_4_0, VS_V1T0N0() ) );\r\n" +
"        SetHullShader( NULL );\r\n" +
"        SetDomainShader( NULL );\r\n" +
"        SetGeometryShader( NULL );\r\n" +
"        SetPixelShader( CompileShader( ps_4_0, PS_T0N0() ) );\r\n" +
"    }\r\n" +
"}\r\n" +
"\r\n" +
"/***********************************************************************/\r\n" +
"/* Case: Vertex Color: False  Texture: True   Normals: False    V0T1N0 */\r\n" +
"/* Case: Vertex Color: True   Texture: True   Normals: False    V1T1N0 */\r\n" +
"/* Case: Texture: True   Normals: False    T1N0 */\r\n" +
"/***********************************************************************/\r\n" +
"\r\n" +
"struct VS_IN_V0T1N0\r\n" +
"{\r\n" +
"    float4 Pos: POSITION;\r\n" +
"    float2 TexC: TEXTURECOORD;\r\n" +
"};\r\n" +
"\r\n" +
"struct VS_IN_V1T1N0\r\n" +
"{\r\n" +
"    float4 Pos: POSITION;\r\n" +
"    float2 TexC: TEXTURECOORD;\r\n" +
"	float4 Col: COLOR;\r\n" +
"};\r\n" +
"\r\n" +
"struct PS_IN_T1N0\r\n" +
"{\r\n" +
"	float4 Pos: SV_POSITION;\r\n" +
"	float2 TexC: TEXTURECOORD;\r\n" +
"	float3 WPos: POSITION;\r\n" +
"	float4 Light: COLOR0;\r\n" +
"};\r\n" +
"\r\n" +
"PS_IN_T1N0 VS_V0T1N0( VS_IN_V0T1N0 input )\r\n" +
"{\r\n" +
"    PS_IN_T1N0 output;\r\n" +
"    output.Pos = mul(input.Pos, mul(World, mul(View, Projection)));\r\n" +
"    output.TexC = input.TexC;\r\n" +
"    output.WPos = mul(input.Pos, World).xyz;\r\n" +
"    output.Light = float4(EmissiveColor + DiffuseColor, Alpha);\r\n" +
"    return output;\r\n" +
"}\r\n" +
"\r\n" +
"PS_IN_T1N0 VS_V1T1N0( VS_IN_V1T1N0 input )\r\n" +
"{\r\n" +
"    PS_IN_T1N0 output;\r\n" +
"    output.Pos = mul(input.Pos, mul(World, mul(View, Projection)));\r\n" +
"    output.TexC = input.TexC;\r\n" +
"    output.WPos = mul(input.Pos, World).xyz;\r\n" +
"    output.Light = float4(EmissiveColor, 0) + input.Col * float4(DiffuseColor, Alpha);\r\n" +
"    return output;\r\n" +
"}\r\n" +
"\r\n" +
"float4 PS_T1N0( PS_IN_T1N0 input ) : SV_Target\r\n" +
"{\r\n" +
"    float4 colourout;\r\n" +
"    colourout = input.Light * Texture.Sample(samLinear, input.TexC);\r\n" +
"    if (FogEnabled)\r\n" +
"    {\r\n" +
"        float foglevel = saturate((length(CameraPosition - input.WPos) - FogStart)\r\n" +
"                                                              / (FogEnd - FogStart));\r\n" +
"        colourout.rgb = colourout.rgb * (1 - foglevel) + FogColor * foglevel;\r\n" +
"    }\r\n" +
"    return colourout;\r\n" +
"}\r\n" +
"\r\n" +
"technique10 Render_V0T1N0\r\n" +
"{\r\n" +
"    pass P0\r\n" +
"    {\r\n" +
"        SetVertexShader( CompileShader( vs_4_0, VS_V0T1N0() ) );\r\n" +
"        SetHullShader( NULL );\r\n" +
"        SetDomainShader( NULL );\r\n" +
"        SetGeometryShader( NULL );\r\n" +
"        SetPixelShader( CompileShader( ps_4_0, PS_T1N0() ) );\r\n" +
"    }\r\n" +
"}\r\n" +
"\r\n" +
"technique10 Render_V1T1N0\r\n" +
"{\r\n" +
"    pass P0\r\n" +
"    {\r\n" +
"        SetVertexShader( CompileShader( vs_4_0, VS_V1T1N0() ) );\r\n" +
"        SetHullShader( NULL );\r\n" +
"        SetDomainShader( NULL );\r\n" +
"        SetGeometryShader( NULL );\r\n" +
"        SetPixelShader( CompileShader( ps_4_0, PS_T1N0() ) );\r\n" +
"    }\r\n" +
"}\r\n" +
"\r\n" +
"\r\n" +
"/***********************************************************************/\r\n" +
"/* Case: Vertex Color: False  Texture: False  Normals: True     V0T0N1 */\r\n" +
"/* Case: Vertex Color: True   Texture: False  Normals: True     V1T0N1 */\r\n" +
"/* Case: Texture: False  Normals: True     T0N1 */\r\n" +
"/***********************************************************************/\r\n" +
"\r\n" +
"struct VS_IN_V0T0N1\r\n" +
"{\r\n" +
"    float4 Pos: POSITION;\r\n" +
"    float3 Norm: NORMAL;\r\n" +
"};\r\n" +
"\r\n" +
"struct VS_IN_V1T0N1\r\n" +
"{\r\n" +
"    float4 Pos: POSITION;\r\n" +
"    float3 Norm: NORMAL;\r\n" +
"	float4 Col: COLOR;\r\n" +
"};\r\n" +
"\r\n" +
"struct PS_IN_T0N1\r\n" +
"{\r\n" +
"	float4 Pos: SV_POSITION;\r\n" +
"	float3 WPos: POSITION;\r\n" +
"	float3 Norm: NORMAL;\r\n" +
"	float4 Light: COLOR0;\r\n" +
"	float3 LightSpecular: COLOR1;\r\n" +
"};\r\n" +
"\r\n" +
"PS_IN_T0N1 VS_V0T0N1( VS_IN_V0T0N1 input )\r\n" +
"{\r\n" +
"    PS_IN_T0N1 output;\r\n" +
"    output.Pos = mul(input.Pos, mul(World, mul(View, Projection)));\r\n" +
"    output.WPos = mul(input.Pos, World).xyz;\r\n" +
"    output.Norm = mul(input.Norm, (float3x3)World);;\r\n" +
"\r\n" +
"    float3 light = float3(1, 1, 1);\r\n" +
"    float3 lightspecular = float3(0, 0, 0);\r\n" +
"	float3 view = normalize(CameraPosition - output.WPos);\r\n" +
"	light = AmbientLightColor;\r\n" +
"	if (DLEnabled0)\r\n" +
"	{\r\n" +
"	    light += saturate(dot(output.Norm, -DLDirection0)) * DLDiffuseColor0;\r\n" +
"	    if (!PerPixelLighting)\r\n" +
"	    {\r\n" +
"			lightspecular += pow(saturate(dot(normalize(view - DLDirection0), output.Norm)),\r\n" +
"			                     SpecularPower) * DLSpecularColor0 * SpecularColor;\r\n" +
"	    }\r\n" +
"	}   \r\n" +
"	if (DLEnabled1)\r\n" +
"	{\r\n" +
"		light += saturate(dot(output.Norm, -DLDirection1)) * DLDiffuseColor1;\r\n" +
"		if (!PerPixelLighting)\r\n" +
"		{\r\n" +
"			lightspecular += pow(saturate(dot(normalize(view - DLDirection1), output.Norm)),\r\n" +
"								 SpecularPower) * DLSpecularColor1 * SpecularColor;\r\n" +
"		}\r\n" +
"	}   \r\n" +
"	if (DLEnabled2)\r\n" +
"	{\r\n" +
"		light += saturate(dot(output.Norm, -DLDirection2)) * DLDiffuseColor2;\r\n" +
"		if (!PerPixelLighting)\r\n" +
"		{\r\n" +
"			lightspecular += pow(saturate(dot(normalize(view - DLDirection2), output.Norm)),\r\n" +
"								 SpecularPower) * DLSpecularColor2 * SpecularColor;\r\n" +
"		}\r\n" +
"	}   \r\n" +
"    output.Light = float4(EmissiveColor + light * DiffuseColor, Alpha);\r\n" +
"    output.LightSpecular = lightspecular;\r\n" +
"    return output;\r\n" +
"}\r\n" +
"\r\n" +
"PS_IN_T0N1 VS_V1T0N1( VS_IN_V1T0N1 input )\r\n" +
"{\r\n" +
"    PS_IN_T0N1 output;\r\n" +
"    output.Pos = mul(input.Pos, mul(World, mul(View, Projection)));\r\n" +
"    output.WPos = mul(input.Pos, World).xyz;\r\n" +
"    output.Norm = mul(input.Norm, (float3x3)World);;\r\n" +
"\r\n" +
"    float3 light = float3(1, 1, 1);\r\n" +
"    float3 lightspecular = float3(0, 0, 0);\r\n" +
"	float3 view = normalize(CameraPosition - output.WPos);\r\n" +
"	light = AmbientLightColor;\r\n" +
"	if (DLEnabled0)\r\n" +
"	{\r\n" +
"	    light += saturate(dot(output.Norm, -DLDirection0)) * DLDiffuseColor0;\r\n" +
"	    if (!PerPixelLighting)\r\n" +
"	    {\r\n" +
"			lightspecular += pow(saturate(dot(normalize(view - DLDirection0), output.Norm)),\r\n" +
"			                     SpecularPower) * DLSpecularColor0 * SpecularColor;\r\n" +
"	    }\r\n" +
"	}   \r\n" +
"	if (DLEnabled1)\r\n" +
"	{\r\n" +
"		light += saturate(dot(output.Norm, -DLDirection1)) * DLDiffuseColor1;\r\n" +
"		if (!PerPixelLighting)\r\n" +
"		{\r\n" +
"			lightspecular += pow(saturate(dot(normalize(view - DLDirection1), output.Norm)),\r\n" +
"								 SpecularPower) * DLSpecularColor1 * SpecularColor;\r\n" +
"		}\r\n" +
"	}   \r\n" +
"	if (DLEnabled2)\r\n" +
"	{\r\n" +
"		light += saturate(dot(output.Norm, -DLDirection2)) * DLDiffuseColor2;\r\n" +
"		if (!PerPixelLighting)\r\n" +
"		{\r\n" +
"			lightspecular += pow(saturate(dot(normalize(view - DLDirection2), output.Norm)),\r\n" +
"								 SpecularPower) * DLSpecularColor2 * SpecularColor;\r\n" +
"		}\r\n" +
"	}   \r\n" +
"    output.Light = float4(EmissiveColor, 0) + input.Col * float4(light * DiffuseColor, Alpha);\r\n" +
"    output.LightSpecular = lightspecular;\r\n" +
"    return output;\r\n" +
"}\r\n" +
"\r\n" +
"float4 PS_T0N1( PS_IN_T0N1 input ) : SV_Target\r\n" +
"{\r\n" +
"    if (PerPixelLighting)\r\n" +
"    {\r\n" +
"		input.Norm = normalize(input.Norm);\r\n" +
"		float3 view = normalize(CameraPosition - input.WPos);\r\n" +
"		if (DLEnabled0)\r\n" +
"			input.LightSpecular += pow(saturate(dot(normalize(view - DLDirection0), input.Norm)),\r\n" +
"				                       SpecularPower) * DLSpecularColor0 * SpecularColor;\r\n" +
"		if (DLEnabled1)\r\n" +
"			input.LightSpecular += pow(saturate(dot(normalize(view - DLDirection1), input.Norm)),\r\n" +
"				                       SpecularPower) * DLSpecularColor1 * SpecularColor;\r\n" +
"		if (DLEnabled2)\r\n" +
"			input.LightSpecular += pow(saturate(dot(normalize(view - DLDirection2), input.Norm)),\r\n" +
"				                       SpecularPower) * DLSpecularColor2 * SpecularColor;\r\n" +
"	}\r\n" +
"   float4 colourout;\r\n" +
"   colourout = input.Light + float4(input.LightSpecular, 0);\r\n" +
"   if (FogEnabled)\r\n" +
"   {\r\n" +
"       float foglevel = saturate((length(CameraPosition - input.WPos) - FogStart)\r\n" +
"                                                             / (FogEnd - FogStart));\r\n" +
"       colourout.rgb = colourout.rgb * (1 - foglevel) + FogColor * foglevel;\r\n" +
"   }\r\n" +
"   return colourout;\r\n" +
"}\r\n" +
"\r\n" +
"technique10 Render_V0T0N1\r\n" +
"{\r\n" +
"    pass P0\r\n" +
"    {\r\n" +
"        SetVertexShader( CompileShader( vs_4_0, VS_V0T0N1() ) );\r\n" +
"        SetHullShader( NULL );\r\n" +
"        SetDomainShader( NULL );\r\n" +
"        SetGeometryShader( NULL );\r\n" +
"        SetPixelShader( CompileShader( ps_4_0, PS_T0N1() ) );\r\n" +
"    }\r\n" +
"}\r\n" +
"\r\n" +
"technique10 Render_V1T0N1\r\n" +
"{\r\n" +
"    pass P0\r\n" +
"    {\r\n" +
"        SetVertexShader( CompileShader( vs_4_0, VS_V1T0N1() ) );\r\n" +
"        SetHullShader( NULL );\r\n" +
"        SetDomainShader( NULL );\r\n" +
"        SetGeometryShader( NULL );\r\n" +
"        SetPixelShader( CompileShader( ps_4_0, PS_T0N1() ) );\r\n" +
"    }\r\n" +
"}\r\n" +
"\r\n" +
"\r\n" +
"/***********************************************************************/\r\n" +
"/* Case: Vertex Color: False  Texture: True   Normals: True     V0T1N1 */\r\n" +
"/* Case: Vertex Color: True   Texture: True   Normals: True     V1T1N1 */\r\n" +
"/* Case: Texture: True   Normals: True     T1N1 */\r\n" +
"/***********************************************************************/\r\n" +
"\r\n" +
"struct VS_IN_V0T1N1\r\n" +
"{\r\n" +
"    float4 Pos: POSITION;\r\n" +
"    float3 Norm: NORMAL;\r\n" +
"    float2 TexC: TEXTURECOORD;\r\n" +
"};\r\n" +
"\r\n" +
"struct VS_IN_V0T1N1Animation\r\n" +
"{\r\n" +
"    float4 Pos: POSITION;\r\n" +
"    uint4 BoneIndices : BLENDINDICES;\r\n" +
"    float4 BoneWeights : BLENDWEIGHTS;\r\n" +
"    float3 Norm: NORMAL;\r\n" +
"    float2 TexC: TEXTURECOORD;\r\n" +
"};\r\n" +
"\r\n" +
"struct VS_IN_V1T1N1\r\n" +
"{\r\n" +
"    float4 Pos: POSITION;\r\n" +
"    float3 Norm: NORMAL;\r\n" +
"    float2 TexC: TEXTURECOORD;\r\n" +
"	float4 Col: COLOR;\r\n" +
"};\r\n" +
"\r\n" +
"struct PS_IN_T1N1\r\n" +
"{\r\n" +
"	float4 Pos: SV_POSITION;\r\n" +
"	float2 TexC: TEXTURECOORD;\r\n" +
"	float3 WPos: POSITION;\r\n" +
"	float3 Norm: NORMAL;\r\n" +
"	float4 Light: COLOR0;\r\n" +
"	float3 LightSpecular: COLOR1;\r\n" +
"};\r\n" +
"\r\n" +
"PS_IN_T1N1 VS_V0T1N1( VS_IN_V0T1N1 input )\r\n" +
"{\r\n" +
"    PS_IN_T1N1 output;\r\n" +
"    output.Pos = mul(input.Pos, mul(World, mul(View, Projection)));\r\n" +
"    output.TexC = input.TexC;\r\n" +
"    output.WPos = mul(input.Pos, World).xyz;\r\n" +
"    output.Norm = mul(input.Norm, (float3x3)World);;\r\n" +
"\r\n" +
"    float3 light = AmbientLightColor;\r\n" +
"    float3 lightspecular = float3(0, 0, 0);\r\n" +
"	float3 view = normalize(CameraPosition - output.WPos);\r\n" +
"	if (DLEnabled0)\r\n" +
"	{\r\n" +
"		light += saturate(dot(output.Norm, -DLDirection0)) * DLDiffuseColor0;\r\n" +
"		if (!PerPixelLighting)\r\n" +
"		{\r\n" +
"			lightspecular += pow(saturate(dot(normalize(view - DLDirection0), output.Norm)),\r\n" +
"								 SpecularPower) * DLSpecularColor0 * SpecularColor;\r\n" +
"		}\r\n" +
"	}   \r\n" +
"	if (DLEnabled1)\r\n" +
"	{\r\n" +
"		light += saturate(dot(output.Norm, -DLDirection1)) * DLDiffuseColor1;\r\n" +
"		if (!PerPixelLighting)\r\n" +
"		{\r\n" +
"			lightspecular += pow(saturate(dot(normalize(view - DLDirection1), output.Norm)),\r\n" +
"								 SpecularPower) * DLSpecularColor1 * SpecularColor;\r\n" +
"		}\r\n" +
"	}   \r\n" +
"	if (DLEnabled2)\r\n" +
"	{\r\n" +
"		light += saturate(dot(output.Norm, -DLDirection2)) * DLDiffuseColor2;\r\n" +
"		if (!PerPixelLighting)\r\n" +
"		{\r\n" +
"			lightspecular += pow(saturate(dot(normalize(view - DLDirection2), output.Norm)),\r\n" +
"								 SpecularPower) * DLSpecularColor2 * SpecularColor;\r\n" +
"		}\r\n" +
"	}   \r\n" +
"    output.Light = float4(EmissiveColor + light * DiffuseColor, Alpha);\r\n" +
"    output.LightSpecular = lightspecular;\r\n" +
"    return output;\r\n" +
"}\r\n" +
"\r\n" +
"PS_IN_T1N1 VS_V0T1N1Animation( VS_IN_V0T1N1Animation input )\r\n" +
"{\r\n" +
"    PS_IN_T1N1 output;\r\n" +
"	\r\n" +
"    float4x4 skinTransform = 0;\r\n" +
"    skinTransform += Bones[input.BoneIndices.x] * input.BoneWeights.x;\r\n" +
"    skinTransform += Bones[input.BoneIndices.y] * input.BoneWeights.y;\r\n" +
"    skinTransform += Bones[input.BoneIndices.z] * input.BoneWeights.z;\r\n" +
"    skinTransform += Bones[input.BoneIndices.w] * input.BoneWeights.w;\r\n" +
"    skinTransform = mul(skinTransform, World);\r\n" +
"    \r\n" +
"    output.Pos = mul(input.Pos, mul(skinTransform, mul(View, Projection)));\r\n" +
"    output.TexC = input.TexC;\r\n" +
"    output.WPos = mul(input.Pos, skinTransform).xyz;\r\n" +
"    output.Norm = mul(input.Norm, (float3x3)skinTransform);;\r\n" +
"\r\n" +
"    float3 light = AmbientLightColor;\r\n" +
"    float3 lightspecular = float3(0, 0, 0);\r\n" +
"	float3 view = normalize(CameraPosition - output.WPos);\r\n" +
"	if (DLEnabled0)\r\n" +
"	{\r\n" +
"		light += saturate(dot(output.Norm, -DLDirection0)) * DLDiffuseColor0;\r\n" +
"		if (!PerPixelLighting)\r\n" +
"		{\r\n" +
"			lightspecular += pow(saturate(dot(normalize(view - DLDirection0), output.Norm)),\r\n" +
"								 SpecularPower) * DLSpecularColor0 * SpecularColor;\r\n" +
"		}\r\n" +
"	}   \r\n" +
"	if (DLEnabled1)\r\n" +
"	{\r\n" +
"		light += saturate(dot(output.Norm, -DLDirection1)) * DLDiffuseColor1;\r\n" +
"		if (!PerPixelLighting)\r\n" +
"		{\r\n" +
"			lightspecular += pow(saturate(dot(normalize(view - DLDirection1), output.Norm)),\r\n" +
"								 SpecularPower) * DLSpecularColor1 * SpecularColor;\r\n" +
"		}\r\n" +
"	}   \r\n" +
"	if (DLEnabled2)\r\n" +
"	{\r\n" +
"		light += saturate(dot(output.Norm, -DLDirection2)) * DLDiffuseColor2;\r\n" +
"		if (!PerPixelLighting)\r\n" +
"		{\r\n" +
"			lightspecular += pow(saturate(dot(normalize(view - DLDirection2), output.Norm)),\r\n" +
"								 SpecularPower) * DLSpecularColor2 * SpecularColor;\r\n" +
"		}\r\n" +
"	}   \r\n" +
"    output.Light = float4(EmissiveColor + light * DiffuseColor, Alpha);\r\n" +
"    output.LightSpecular = lightspecular;\r\n" +
"    return output;\r\n" +
"}\r\n" +
"\r\n" +
"PS_IN_T1N1 VS_V1T1N1( VS_IN_V1T1N1 input )\r\n" +
"{\r\n" +
"    PS_IN_T1N1 output;\r\n" +
"    output.Pos = mul(input.Pos, mul(World, mul(View, Projection)));\r\n" +
"    output.TexC = input.TexC;\r\n" +
"    output.WPos = mul(input.Pos, World).xyz;\r\n" +
"    output.Norm = mul(input.Norm, (float3x3)World);;\r\n" +
"\r\n" +
"    float3 light = AmbientLightColor;\r\n" +
"    float3 lightspecular = float3(0, 0, 0);\r\n" +
"	float3 view = normalize(CameraPosition - output.WPos);\r\n" +
"	if (DLEnabled0)\r\n" +
"	{\r\n" +
"		light += saturate(dot(output.Norm, -DLDirection0)) * DLDiffuseColor0;\r\n" +
"		if (!PerPixelLighting)\r\n" +
"		{\r\n" +
"			lightspecular += pow(saturate(dot(normalize(view - DLDirection0), output.Norm)),\r\n" +
"								 SpecularPower) * DLSpecularColor0 * SpecularColor;\r\n" +
"		}\r\n" +
"	}   \r\n" +
"	if (DLEnabled1)\r\n" +
"	{\r\n" +
"		light += saturate(dot(output.Norm, -DLDirection1)) * DLDiffuseColor1;\r\n" +
"		if (!PerPixelLighting)\r\n" +
"		{\r\n" +
"			lightspecular += pow(saturate(dot(normalize(view - DLDirection1), output.Norm)),\r\n" +
"								 SpecularPower) * DLSpecularColor1 * SpecularColor;\r\n" +
"		}\r\n" +
"	}   \r\n" +
"	if (DLEnabled2)\r\n" +
"	{\r\n" +
"		light += saturate(dot(output.Norm, -DLDirection2)) * DLDiffuseColor2;\r\n" +
"		if (!PerPixelLighting)\r\n" +
"		{\r\n" +
"			lightspecular += pow(saturate(dot(normalize(view - DLDirection2), output.Norm)),\r\n" +
"								 SpecularPower) * DLSpecularColor2 * SpecularColor;\r\n" +
"		}\r\n" +
"	}   \r\n" +
"    output.Light = float4(EmissiveColor, 0) + input.Col * float4(light * DiffuseColor, Alpha);\r\n" +
"    output.LightSpecular = lightspecular;\r\n" +
"    return output;\r\n" +
"}\r\n" +
"\r\n" +
"float4 PS_T1N1( PS_IN_T1N1 input ) : SV_Target\r\n" +
"{\r\n" +
"    if (PerPixelLighting)\r\n" +
"    {\r\n" +
"		input.Norm = normalize(input.Norm);\r\n" +
"		float3 view = normalize(CameraPosition - input.WPos);\r\n" +
"		if (DLEnabled0)\r\n" +
"			input.LightSpecular += pow(saturate(dot(normalize(view - DLDirection0), input.Norm)),\r\n" +
"				                       SpecularPower) * DLSpecularColor0 * SpecularColor;\r\n" +
"		if (DLEnabled1)\r\n" +
"			input.LightSpecular += pow(saturate(dot(normalize(view - DLDirection1), input.Norm)),\r\n" +
"				                       SpecularPower) * DLSpecularColor1 * SpecularColor;\r\n" +
"		if (DLEnabled2)\r\n" +
"			input.LightSpecular += pow(saturate(dot(normalize(view - DLDirection2), input.Norm)),\r\n" +
"				                       SpecularPower) * DLSpecularColor2 * SpecularColor;\r\n" +
"	}\r\n" +
"    float4 colourout;\r\n" +
"    colourout = input.Light * Texture.Sample(samLinear, input.TexC) + float4(input.LightSpecular, 0);\r\n" +
"    if (FogEnabled)\r\n" +
"    {\r\n" +
"        float foglevel = saturate((length(CameraPosition - input.WPos) - FogStart)\r\n" +
"                                                              / (FogEnd - FogStart));\r\n" +
"        colourout.rgb = colourout.rgb * (1 - foglevel) + FogColor * foglevel;\r\n" +
"    }\r\n" +
"    return colourout;\r\n" +
"}\r\n" +
"\r\n" +
"technique10 Render_V0T1N1\r\n" +
"{\r\n" +
"    pass P0\r\n" +
"    {\r\n" +
"        SetVertexShader( CompileShader( vs_4_0, VS_V0T1N1() ) );\r\n" +
"        SetHullShader( NULL );\r\n" +
"        SetDomainShader( NULL );\r\n" +
"        SetGeometryShader( NULL );\r\n" +
"        SetPixelShader( CompileShader( ps_4_0, PS_T1N1() ) );\r\n" +
"    }\r\n" +
"}\r\n" +
"\r\n" +
"technique10 Render_V0T1N1Animation\r\n" +
"{\r\n" +
"    pass P0\r\n" +
"    {\r\n" +
"        SetVertexShader( CompileShader( vs_4_0, VS_V0T1N1Animation() ) );\r\n" +
"        SetHullShader( NULL );\r\n" +
"        SetDomainShader( NULL );\r\n" +
"        SetGeometryShader( NULL );\r\n" +
"        SetPixelShader( CompileShader( ps_4_0, PS_T1N1() ) );\r\n" +
"    }\r\n" +
"}\r\n" +
"\r\n" +
"technique10 Render_V1T1N1\r\n" +
"{\r\n" +
"    pass P0\r\n" +
"    {\r\n" +
"        SetVertexShader( CompileShader( vs_4_0, VS_V1T1N1() ) );\r\n" +
"        SetHullShader( NULL );\r\n" +
"        SetDomainShader( NULL );\r\n" +
"        SetGeometryShader( NULL );\r\n" +
"        SetPixelShader( CompileShader( ps_4_0, PS_T1N1() ) );\r\n" +
"    }\r\n" +
"};\r\n";
        #endregion

        Microsoft.Xna.Framework.Matrix world = Microsoft.Xna.Framework.Matrix.Identity;
        Microsoft.Xna.Framework.Matrix view = Microsoft.Xna.Framework.Matrix.Identity;
        Microsoft.Xna.Framework.Vector3 cameraposition = Microsoft.Xna.Framework.Vector3.Zero;
        Microsoft.Xna.Framework.Matrix projection = Microsoft.Xna.Framework.Matrix.Identity;
        Texture2D texture = null;
        float alpha = 1;
        Microsoft.Xna.Framework.Vector3 ambientlightcolor = new Microsoft.Xna.Framework.Vector3(0, 0, 0);
        Microsoft.Xna.Framework.Vector3 diffusecolor = new Microsoft.Xna.Framework.Vector3(1, 1, 1);
        Microsoft.Xna.Framework.Vector3 emissivecolor = new Microsoft.Xna.Framework.Vector3(0, 0, 0);
        Microsoft.Xna.Framework.Vector3 specularcolor = new Microsoft.Xna.Framework.Vector3(1, 1, 1);
        float specularpower = 16;
        BasicDirectionalLight dirlight0, dirlight1, dirlight2;
        Microsoft.Xna.Framework.Vector3 fogcolor = new Microsoft.Xna.Framework.Vector3(0, 0, 0);
        bool fogenabled = false;
        float fogend = 1, fogstart = 0;
        bool perpixellighting = false;

        // Flags enabled by choice of shader technique
        bool vertexcolorenabled = false;
        bool lightingenabled = false;
        bool textureenabled = false;
        bool useforanimation = false;  // Only support animation with texture and normals and no vertex colour

        // Effect caches shader code on request - it returns an id to identify the cached code
        static int cacheid = -1;

        public Microsoft.Xna.Framework.Matrix World
        {
            get
            {
                return world;
            }
            set
            {
                world = value;
                Parameters["World"].SetValue(world);
            }
        }
        public Microsoft.Xna.Framework.Matrix View
        {
            get
            {
                return view;
            }
            set
            {
                view = value;
                cameraposition = Microsoft.Xna.Framework.Matrix.Invert(view).Translation;
                Parameters["View"].SetValue(view);
            }
        }
        public Microsoft.Xna.Framework.Matrix Projection
        {
            get
            {
                return projection;
            }
            set
            {
                projection = value;
                Parameters["Projection"].SetValue(projection);
            }
        }
        public Texture2D Texture
        {
            get
            {
                return texture;
            }
            set
            {
                texture = value;
                Parameters["Texture"].SetValue(texture);
            }
        }
        public bool TextureEnabled
        {
            get
            {
                return textureenabled;
            }
            set
            {
                textureenabled = value;
            }
        }
        internal bool UseForAnimation
        {
            get { return useforanimation; }
            set { useforanimation = value; }
        }
        public float Alpha
        {
            get
            {
                return alpha;
            }
            set
            {
                alpha = value;
                Parameters["Alpha"].SetValue(alpha);
            }
        }
        public Microsoft.Xna.Framework.Vector3 AmbientLightColor
        {
            get
            {
                return ambientlightcolor;
            }
            set
            {
                ambientlightcolor = value;
                Parameters["AmbientLightColor"].SetValue(ambientlightcolor);
            }
        }
        public Microsoft.Xna.Framework.Vector3 DiffuseColor
        {
            get
            {
                return diffusecolor;
            }
            set
            {
                diffusecolor = value;
                Parameters["DiffuseColor"].SetValue(diffusecolor);
            }
        }
        public Microsoft.Xna.Framework.Vector3 EmissiveColor
        {
            get
            {
                return emissivecolor;
            }
            set
            {
                emissivecolor = value;
                Parameters["EmissiveColor"].SetValue(emissivecolor);
            }
        }
        public Microsoft.Xna.Framework.Vector3 SpecularColor
        {
            get
            {
                return specularcolor;
            }
            set
            {
                specularcolor = value;
                Parameters["SpecularColor"].SetValue(specularcolor);
            }
        }
        public float SpecularPower
        {
            get
            {
                return specularpower;
            }
            set
            {
                specularpower = value;
                Parameters["SpecularPower"].SetValue(specularpower);
            }
        }

        public BasicDirectionalLight DirectionalLight0 { get { return dirlight0; } }
        public BasicDirectionalLight DirectionalLight1 { get { return dirlight1; } }
        public BasicDirectionalLight DirectionalLight2 { get { return dirlight2; } }

        public Microsoft.Xna.Framework.Vector3 FogColor
        {
            get
            {
                return fogcolor;
            }
            set
            {
                fogcolor = value;
                Parameters["FogColor"].SetValue(fogcolor);
            }
        }
        public bool FogEnabled
        {
            get
            {
                return fogenabled;
            }
            set
            {
                fogenabled = value;
                Parameters["FogEnabled"].SetValue(fogenabled);
            }
        }
        public float FogEnd
        {
            get
            {
                return fogend;
            }
            set
            {
                fogend = value;
                Parameters["FogEnd"].SetValue(fogend);
            }
        }
        public float FogStart
        {
            get
            {
                return fogstart;
            }
            set
            {
                fogstart = value;
                Parameters["FogStart"].SetValue(fogstart);
            }
        }

        public bool LightingEnabled
        {
            get
            {
                return lightingenabled;
            }
            set
            {
                lightingenabled = value;
            }
        }
        public bool PreferPerPixelLighting
        {
            get
            {
                return perpixellighting;
            }
            set
            {
                perpixellighting = value;
                Parameters["PerPixelLighting"].SetValue(perpixellighting);
            }
        }
        public bool VertexColorEnabled
        {
            get
            {
                return vertexcolorenabled;
            }
            set
            {
                vertexcolorenabled = value;
            }
        }

        public BasicEffect(GraphicsDevice dev)
            : base(ShaderSource, ref cacheid)
        {
            dirlight0 = new BasicDirectionalLight(this, "0");
            dirlight1 = new BasicDirectionalLight(this, "1");
            dirlight2 = new BasicDirectionalLight(this, "2");
        }

        internal BasicEffect(GraphicsDevice device, string shadersource, string junk)
            : base(shadersource)
        {
            dirlight0 = new BasicDirectionalLight(this, "0");
            dirlight1 = new BasicDirectionalLight(this, "1");
            dirlight2 = new BasicDirectionalLight(this, "2");
        }

        public void EnableDefaultLighting()
        {
            LightingEnabled = true;
            AmbientLightColor = new Microsoft.Xna.Framework.Vector3(0.05333332f, 0.09882354f, 0.1819608f);

            DirectionalLight0.DiffuseColor = new Microsoft.Xna.Framework.Vector3(1, 0.9607844f, 0.8078432f);
            DirectionalLight0.Direction = new Microsoft.Xna.Framework.Vector3(-0.5265408f, -0.5735765f, -0.6275069f);
            DirectionalLight0.SpecularColor = new Microsoft.Xna.Framework.Vector3(1, 0.9607844f, 0.8078432f);
            DirectionalLight0.Enabled = true;

            DirectionalLight1.DiffuseColor = new Microsoft.Xna.Framework.Vector3(0.9647059f, 0.7607844f, 0.4078432f);
            DirectionalLight1.Direction = new Microsoft.Xna.Framework.Vector3(0.7198464f, 0.3420201f, 0.6040227f);
            DirectionalLight1.SpecularColor = new Microsoft.Xna.Framework.Vector3(0, 0, 0);
            DirectionalLight1.Enabled = true;

            DirectionalLight2.DiffuseColor = new Microsoft.Xna.Framework.Vector3(0.3231373f, 0.3607844f, 0.3937255f);
            DirectionalLight2.Direction = new Microsoft.Xna.Framework.Vector3(0.4545195f, -0.7660444f, 0.4545195f);
            DirectionalLight2.SpecularColor = new Microsoft.Xna.Framework.Vector3(0.3231373f, 0.3607844f, 0.3937255f);
            DirectionalLight2.Enabled = true;
        }

        public override void Begin()
        {
            Parameters["CameraPosition"].SetValue(cameraposition);
            if (useforanimation)
                CurrentTechnique = Techniques["Render_V0T1N1Animation"];
            else
                CurrentTechnique = Techniques["Render_" + (vertexcolorenabled ? "V1" : "V0")
                                                        + (textureenabled ? "T1" : "T0")
                                                        + (lightingenabled ? "N1" : "N0")];
            base.Begin();
        }
    }

    public sealed class BasicDirectionalLight
    {
        Effect effect;
        string index;
        Microsoft.Xna.Framework.Vector3 diffusecolor, direction, specularcolor;
        bool enabled;

        public BasicDirectionalLight(Effect eff, string i)
        {
            effect = eff;
            index = i;
            diffusecolor = new Microsoft.Xna.Framework.Vector3(0, 0, 0);
            direction = new Microsoft.Xna.Framework.Vector3(0, 1, 0);
            specularcolor = new Microsoft.Xna.Framework.Vector3(0, 0, 0);
            enabled = false;
        }

        public Microsoft.Xna.Framework.Vector3 DiffuseColor
        {
            get
            {
                return diffusecolor;
            }
            set
            {
                diffusecolor = value;
                effect.Parameters["DLDiffuseColor" + index].SetValue(diffusecolor);
            }
        }
        public Microsoft.Xna.Framework.Vector3 Direction
        {
            get
            {
                return direction;
            }
            set
            {
                direction = value;
                effect.Parameters["DLDirection" + index].SetValue(direction);
            }
        }
        public Microsoft.Xna.Framework.Vector3 SpecularColor
        {
            get
            {
                return specularcolor;
            }
            set
            {
                specularcolor = value;
                effect.Parameters["DLSpecularColor" + index].SetValue(specularcolor);
            }
        }
        public bool Enabled
        {
            get
            {
                return enabled;
            }
            set
            {
                enabled = value;
                effect.Parameters["DLEnabled" + index].SetValue(enabled);
            }
        }
    }
}




/*
    // Summary:
    //     Represents shader model 1.1 Effect that has optional support for vertex colors,
    //     texturing, and lighting. Reference page contains links to related code samples.
    public class BasicEffect : Effect
    {
        // Summary:
        //     Initializes a new instance of the BasicEffect class.
        //
        // Parameters:
        //   device:
        //     The graphics device that will create the effect.
        //
        //   clone:
        //     The effect to clone.
        protected BasicEffect(GraphicsDevice device, BasicEffect clone);

        // Summary:
        //     Creates a clone of an effect.
        //
        // Parameters:
        //   device:
        //     The cloned effect.
        public override Effect Clone(GraphicsDevice device);
*/
